package com.hog.service.common.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.StringUtil;
import com.hog.datasource.HogDataSourceConfig;
import com.hog.service.common.IBaseService;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import tk.mybatis.mapper.common.BaseMapper;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.UUID;

/**
 * Service 基类
 *
 * @author 糖先森
 * @date 2018年03月29日
 * @since JDK 1.8
 */
public class BaseServiceImpl<T, M extends Mapper<T>> implements IBaseService<T> {
    private static final Logger LOG = LoggerFactory.getLogger(BaseServiceImpl.class);
    private static final String TABLE_PRIMARY_KEY = "id";
    private static final int BATCH_COUNT = 500;

    @Autowired
    private ApplicationContext appContext;

    @Autowired
    protected M mapper;

    @Override
    public int insert(T entity) {
        return mapper.insert(entity);
    }

    @Override
    public int insertSelective(T entity) {
        return mapper.insertSelective(entity);
    }

    @Override
    public int saveOrUpdate(T entity) {
        try {
            String id = BeanUtilsBean.getInstance().getProperty(entity, TABLE_PRIMARY_KEY);
            if (StringUtil.isNotEmpty(id)) {
                return mapper.updateByPrimaryKey(entity);
            } else {
                BeanUtilsBean.getInstance().setProperty(entity, TABLE_PRIMARY_KEY, UUID.randomUUID());
                return mapper.insertSelective(entity);
            }
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            return -1;
        }
    }

    @Override
    @SuppressWarnings("unchecked")
    public void insertBatch(List<T> data) {
        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) appContext.getBean(HogDataSourceConfig.BEAN_NAME_HOG_SQL_SESSION_FACTORY);
        SqlSession batchSqlSession = null;
        try {
            batchSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
            // 判断当前mapper是否实现了tk.mybatis.mapper.common.BaseMapper接口
            Class<?>[] interfaces = mapper.getClass().getInterfaces();
            Class clazz = null;
            for (int i = 0; i < interfaces.length; i++) {
                if (BaseMapper.class.isAssignableFrom(interfaces[i])) {
                    clazz = interfaces[i];
                }
            }
            if (clazz == null) {
                throw new Exception("user-defined exception:mapper not implements interfaces tk.mybatis.mapper.common.BaseMapper");
            }
            // 从当前batchSqlSession中取baseMapper，mapper的SqlSession与batchSqlSession不是同一个会话
            BaseMapper baseMapper = (BaseMapper) batchSqlSession.getMapper(clazz);
            for (int index = 0; index < data.size(); index++) {
                baseMapper.insert(data.get(index));
                if (index != 0 && index % BATCH_COUNT == 0) {
                    batchSqlSession.commit();
                }
            }
            batchSqlSession.commit();
        } catch (Exception e) {
            LOG.error("BaseServiceImpl insertBatch has exception", e);
        } finally {
            if (batchSqlSession != null) {
                batchSqlSession.close();
            }
        }
    }

    @Override
    public int delete(T entity) {
        return mapper.delete(entity);
    }

    @Override
    public int deleteByExample(Example example) {
        return mapper.deleteByExample(example);
    }

    @Override
    public int deleteByPrimaryKey(Object key) {
        return mapper.deleteByPrimaryKey(key);
    }

    @Override
    public int updateByExample(T entity, Example example) {
        return mapper.updateByExample(entity, example);
    }

    @Override
    public int updateByExampleSelective(T entity, Example example) {
        return mapper.updateByExampleSelective(entity, example);
    }

    @Override
    public int updateByPrimaryKey(T entity) {
        return mapper.updateByPrimaryKey(entity);
    }

    @Override
    public int updateByPrimaryKeySelective(T entity) {
        return mapper.updateByPrimaryKeySelective(entity);
    }

    @Override
    @SuppressWarnings("unchecked")
    public void updateBatch(List<T> data) {
        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) appContext.getBean(HogDataSourceConfig.BEAN_NAME_HOG_SQL_SESSION_FACTORY);
        SqlSession batchSqlSession = null;
        try {
            batchSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
            // 判断当前mapper是否实现了tk.mybatis.mapper.common.BaseMapper接口
            Class<?>[] interfaces = mapper.getClass().getInterfaces();
            Class clazz = null;
            for (int i = 0; i < interfaces.length; i++) {
                if (BaseMapper.class.isAssignableFrom(interfaces[i])) {
                    clazz = interfaces[i];
                }
            }
            if (clazz == null) {
                throw new Exception("user-defined exception:mapper not implements interfaces tk.mybatis.mapper.common.BaseMapper");
            }
            // 从当前batchSqlSession中取baseMapper，mapper的SqlSession与batchSqlSession不是同一个会话
            BaseMapper baseMapper = (BaseMapper) batchSqlSession.getMapper(clazz);
            for (int index = 0; index < data.size(); index++) {
                baseMapper.updateByPrimaryKeySelective(data.get(index));
                if (index != 0 && index % BATCH_COUNT == 0) {
                    batchSqlSession.commit();
                }
            }
            batchSqlSession.commit();
        } catch (Exception e) {
            LOG.error("BaseServiceImpl updateBatch has exception", e);
        } finally {
            if (batchSqlSession != null) {
                batchSqlSession.close();
            }
        }
    }

    @Override
    public List<T> select(T entity) {
        return mapper.select(entity);
    }

    @Override
    public List<T> selectAll() {
        return mapper.selectAll();
    }

    @Override
    public List<T> selectByExample(Example example) {
        return mapper.selectByExample(example);
    }

    @Override
    public List<T> selectByExampleAndRowBounds(Example example, RowBounds rowBounds) {
        return mapper.selectByExampleAndRowBounds(example, rowBounds);
    }

    @Override
    public List<T> selectByRowBounds(T entity, RowBounds rowBounds) {
        return mapper.selectByRowBounds(entity, rowBounds);
    }

    @Override
    public T selectByPrimaryKey(Object key) {
        return mapper.selectByPrimaryKey(key);
    }

    @Override
    public int selectCount(T entity) {
        return mapper.selectCount(entity);
    }

    @Override
    public int selectCountByExample(Example example) {
        return mapper.selectCountByExample(example);
    }

    @Override
    public T selectOne(T entity) {
        return mapper.selectOne(entity);
    }

    @Override
    public List<T> selectByPage(T entity, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return select(entity);
    }

    @Override
    public List<T> selectAllByPage(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return selectAll();
    }

    @Override
    public List<T> selectByExampleAndPage(Example example, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        return selectByExample(example);
    }
}